/**
 * @author: 團長
 * @date: 2014-2-12-上午9:54:39
 */
package net.loyintean.pearlshell.task.bus;

import java.util.List;
import java.util.concurrent.FutureTask;

import org.apache.log4j.Logger;

import net.loyintean.pearlshell.base.model.ILogInfo;
import net.loyintean.pearlshell.base.model.IResult;
import net.loyintean.pearlshell.base.model.impl.LogInfoFactory;
import net.loyintean.pearlshell.base.model.impl.ResultFactory;

/**
 * Basic implements for ITaskDestributeService. This class fetches a list of
 * task from ITaskFactory, processes the tasks, destributes them to
 * ITaskExecuteService, then manages some processes after all.
 * <p>
 * So this class only takes the responsibility of ordonnace the tasks. It's
 * ITaskFactory to produces the list of task, and the ITaskExecuteService to
 * execute them.
 * <p>
 * This class needs a implements of ITaskFactory. The ITaskFactory provides the
 * tasks for this class.
 * <p>
 * This class contains a default ITaskExecuteService as
 * BasicTaskExecuteServImpl. The ITaskExecuteService executes the tasks. You
 * might specifies another one through the constructor or setter.
 * 
 * <p>
 * This class provides a {@link #beforeProcess(IResult)} and
 * {@link #afterProecess(IResult)} which returns the parameter by default. You
 * might override the two methods for your logic.
 * 
 * @author 團長
 * @since 2014-2-12
 * @version 1.0.0
 */
public class BasicTaskDestServImpl<T> implements ITaskDestributeService<T> {

	/**
	 * logger
	 * 
	 * @author 團長
	 * @since 2014-2-17
	 */
	protected final Logger LOGGER = Logger.getLogger(this.getClass());

	/**
	 * this factory provides the tasks for this destribute service.
	 * 
	 * @author 團長
	 * @since 2014-2-17
	 */
	private ITaskFactory<T> taskFactory;

	/**
	 * this executor execute the tasks of this destribute service.
	 * 
	 * @author 團長
	 * @since 2014-2-17
	 */
	private ITaskExecuteService<T> executor;

	/**
	 * default constructor. The executor is assigned as BasicTaskExecuteServImpl
	 * by default.
	 * <p>
	 * you might assign the taskFactory by {@link #setTaskFactory(ITaskFactory)}
	 * 
	 * @author 團長
	 * @since 2014-2-17
	 */
	public BasicTaskDestServImpl() {
		super();
		this.executor = new BasicTaskExecuteServImpl<T>();
	}

	/**
	 * constructor which specified ITaskFactory. The executor is assigned as
	 * BasicTaskExecuteServImpl, and the taskFactory will be assigned as the
	 * parameter.
	 * 
	 * @author 團長
	 * @since 2014-2-17
	 * @param _taskFactory
	 */
	public BasicTaskDestServImpl(ITaskFactory<T> _taskFactory) {
		super();
		executor = new BasicTaskExecuteServImpl<T>();
		this.taskFactory = _taskFactory;
	}

	/**
	 * constructor which specified both taskFactory and executor.
	 * 
	 * @author 團長
	 * @since 2014-2-17
	 * @param _taskFactory
	 * @param _executor
	 */
	public BasicTaskDestServImpl(ITaskFactory<T> _taskFactory,
			ITaskExecuteService<T> _executor) {
		super();
		executor = _executor;
		this.taskFactory = _taskFactory;
	}

	/**
	 * 
	 * @author 團長
	 * @since 2014-2-12
	 * @see com.sinosig.evaluation.base.service.task.ITaskDestributeService#executeTask()
	 * 
	 */
	@Override
	public IResult<T> destributeTask(Object... taskDatas) {

		IResult<T> result = ResultFactory.INIT();

		assert taskDatas != null;
		

		ILogInfo logInfo = generateLogStub(taskDatas);

		LOGGER.info(logInfo.start());

		List<FutureTask<T>> tasks = taskFactory.produceTasks(taskDatas);

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug(logInfo.inner("&tasks is: " + tasks));
		}

		result = beforeProcess(result, tasks, taskDatas);

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug(logInfo.inner("&result of beforeProcess() is: "
					+ result));
		}

		if (result.isInit() || result.isSuccess()) {

			result = executor.executeTasks(tasks, result);

			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug(logInfo
						.inner("&result of  executor.executeTasks() is: "
								+ result));
			}
		}

		if (result.isSuccess()) {
			result = afterProecess(result, tasks, taskDatas);

			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug(logInfo.inner("&result of  afterProecess() is: "
						+ result));
			}
		}

		LOGGER.info(logInfo.end("&resut=" + result));
		return result;
	}

	/**
	 * generate stub info for logger
	 * 
	 * @author 團長
	 * @since 2014-2-17
	 * @param taskDatas
	 * @return
	 */
	private ILogInfo generateLogStub(Object... taskDatas) {
		ILogInfo logInfo;

		if (taskDatas.length > 0) {
			StringBuilder logInfoBuidler = new StringBuilder("@taskDatas=[");
			for (int i = 0; i < taskDatas.length; i++) {
				logInfoBuidler.append(taskDatas[i]);
				logInfoBuidler.append(",");
			}
			logInfoBuidler.append("]");
			logInfo = LogInfoFactory.BUILD(logInfoBuidler.toString());
		} else {
			logInfo = LogInfoFactory.BUILD("@taskDatas=null");
		}

		return logInfo;
	}

	/**
	 * deal with the tasks and reult before destribute them to executor.
	 * <p>
	 * the default method do nothing but return the _result.
	 * 
	 * @author 團長
	 * @since 2014-2-17
	 * @param _result
	 * @param _tasks
	 * @param taskDatas
	 * @return
	 */
	protected IResult<T> beforeProcess(IResult<T> _result,
			List<FutureTask<T>> _tasks, Object... taskDatas) {
		return _result;
	}

	/**
	 * deal with the tasks and reult after destribute them to executor.
	 * <p>
	 * the default method do nothing but return the _result.
	 * 
	 * @author 團長
	 * @since 2014-2-17
	 * @param _result
	 * @param _tasks
	 * @param taskDatas
	 * @return
	 */
	protected IResult<T> afterProecess(IResult<T> _result,
			List<FutureTask<T>> _tasks, Object... taskDatas) {
		return _result;
	}

	/**
	 * you might assign the taskFactory by this method under spring.
	 * 
	 * @param taskFactory
	 *            the {@link #taskFactory }to set
	 */
	public void setTaskFactory(ITaskFactory<T> taskFactory) {
		this.taskFactory = taskFactory;
	}

	/**
	 * 
	 * you might assign the executor by this method under spring.
	 * 
	 * @param executor
	 *            the {@link #executor }to set
	 */
	public void setExecutor(ITaskExecuteService<T> executor) {
		this.executor = executor;
	}

}